Utility.php

<?php

namespace Taeluf\Tester;

class Utility {

    static public function xdotoolRefreshFirefox($switchBackToWindow = false){
        $args = $switchBackToWindow ? ' y' : '';
        system(__DIR__.'/reload.sh'.$args);

        \Taeluf\Tester\Utility::xdotoolRefreshFirefox($switchBackToWindow);
    }


    static public function startOb(){
        ob_start();
        $ob_level = ob_get_level();
        return $ob_level;
    }
    static public function endOb($ob_level){
        $output = '';

        while (ob_get_level()>$ob_level){
            $output .= ob_get_clean()."\n";
        }
        $output .= ob_get_clean();
        return $output;
    }

    /**
     * call `$allTestsOutput = \Taeluf\Tester::runDirectory($dirPath)` to require all php files in a directory & return & output their results to `$dirPath.'/all-tests.html'
     * Or call `::runDirectory([$dir1, $dir2, ...]);`
     * 
     * @export(RunTest.Directory)
     */
    static public function runDirectory($dir, $outputDir = null){

        $testSet = [];
        
        $list = $dir;
        if (!is_array($dir))$list = [$dir];
        $list = array_values($list);
        foreach ($list as $dir){
            $testSet[$dir] = [];

            $files = scandir($dir);
            $files = array_filter($files,function($file){if (substr($file,-4)=='.php')return $file;});

            foreach ($files as $file){
                $ob_level = static::startOb();

                if (is_dir($dir.'/'.$file)||!is_file($dir.'/'.$file))continue;
                require_once($dir.'/'.$file); 
                $class = static::getClassFromFile($dir.'/'.$file);
                if ($class==null)continue;
                $tester = new $class();
                $results = $tester->run();
                $output = static::endOb($ob_level);

                $testSet[$dir][$class] = ['file'=>$dir.'/'.$file, 'object'=>$tester, 'tests'=>$results];
            }
        }

        return $testSet;
//I'm trying to return something like this:
        // $allCompletedTests = [
            // 'dir'=>[
                // '\\Clasname\\That\\Was\\Tested'=>
                // [
                    // 'file'=> 'file path',
                    // 'object' => $theTesterInstance,
                    // 'tests'=> [
        //                // for function testMethodName()
                        // 'MethodName' => $resultObject
                    // ]//or should this be an array of the testers??
                // ],
                // '\\Another\\Class' => $andItsTests
            // ]
        // ];
    }


    /**
     * Copyright 2021 Reed Sutman, Taeluf
     * MIT License
     * See tluf.me/utils
     *
     * Please retain this notice
     */
    static public function getClassFromFile($file){
        if (is_dir($file)||!is_file($file)){
            return null;
            // throw new \Exception("'$file' is not a file");
        }
        $fp = fopen($file, 'r');
        $class = $namespace = $buffer = '';
        $i = 0;
        while (!$class) {
            if (feof($fp)) break;

            $buffer .= fread($fp, 512);
            ob_start();
            $tokens = @token_get_all($buffer);
            $err = ob_get_clean();

            if (strpos($buffer, '{') === false) continue;

            for (;$i<count($tokens);$i++) {
                if ($tokens[$i][0] === T_NAMESPACE) {
                    for ($j=$i+1;$j<count($tokens); $j++) {
                        if ($tokens[$j][0] === T_STRING) {
                            $namespace .= '\\'.$tokens[$j][1];
                        } else if ($tokens[$j] === '{' || $tokens[$j] === ';') {
                            break;
                        }
                    }
                }

                if ($tokens[$i][0] === T_CLASS) {
                    for ($j=$i+1;$j<count($tokens);$j++) {
                        if ($tokens[$j] === '{') {
                            $class = $tokens[$i+2][1];
                        }
                    }
                }
            }
        }
        if ($class=='')return '';
        return $namespace.'\\'.$class;
        
    }
}